#include "keyboard.h"
#include "keyboard_private.h"

#include "../shared/key_consts.h"
#include "../command_handler.h"
#include "../../shared/bus_definitions.h"


unsigned short keymap[88];  // mapping between rows/columns and key numbers

// variables for detecting button changes.
unsigned short previousState[11];
unsigned short currentState[11];

/**
 * Read initial keyboard states
 **/
void KBD_init(){
  unsigned short row=0;
  for(row = 0; row < ROWCOUNT; row++){
    DATA_BUS_DIRECTION = DATA_IN;
    ADDRESS_BUS = row | SEL_DATA_IN; //Set address and select data input
    delay_ms(1);
    currentState[row] = DATA_BUS;
    previousState[row] = currentState[row];
  }
  KBD_DISABLE = 1;
  KEYMAP_init(keymap);
}

/**
 * Read all keys on the current row and raise a key pressed/released event
 **/
void KBD_read(unsigned short row){

  //read the keyboard
  DATA_BUS_DIRECTION = DATA_IN;
  
  KBD_DISABLE = 0;

  ADDRESS_BUS.F0 = row.F0;
  ADDRESS_BUS.F1 = row.F1;
  ADDRESS_BUS.F2 = row.F2;
  ADDRESS_BUS.F3 = row.F3;
  delay_ms(1);
  currentState[row] = DATA_BUS;
  KBD_DISABLE = 1;

  //check if a button is pressed or released.
  if( currentState[row] != previousState[row]) {
    KBD_generateEvents( row, ~currentState[row] & previousState[row], KEYDIR_DOWN ); //press
    KBD_generateEvents( row, currentState[row] & ~previousState[row], KEYDIR_UP ); //release
  }
  previousState[row] = currentState[row];
}

/**
 * Handle pressed keys. If press = 1, a keyPressed event is added, else a
 * keyReleased is added.
 **/
void KBD_generateEvents( unsigned short row, unsigned short states, unsigned short keydirection ) {

  unsigned short col;
  unsigned short keyPressed;
  unsigned short keyCode;

  //loop through all 8 bits.
  for( col=0; col < 8; col++){
    keyPressed = states & (1<<col);

    if( keyPressed ) {
      keyCode = keymap[row*8+col]; //lookup ID of key pressed.
      CMD_keyEventDispatcher(keyCode, keydirection);
    }
  }
}